package com.zzyl.job;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.zzyl.constant.CacheConstants;
import com.zzyl.mapper.AlertRuleMapper;
import com.zzyl.vo.AlertRuleVo;
import com.zzyl.vo.DeviceDataVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description AlertDataTask
 * @Author jun
 * @Date 2025-09-16
 */
@Component
@Slf4j
public class AlertDataTask {

    @Autowired
    private AlertRuleMapper alertRuleMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 定时任务 每隔一分钟触发一次
     */
    @Scheduled(cron = "0 * * * * ?")
    public void executeTask() {
        log.info("定时任务开始执行：{}", LocalDateTime.now());

        // 查询所有规则
        List<AlertRuleVo> alertRuleList = alertRuleMapper.listAll();

        // 空则结束
        if (ObjectUtil.isEmpty(alertRuleList)) {
            return;
        }

        // 从缓存中获取所有设备上报数据并判断是否非空
        Map<Object, Object> hashValues = redisTemplate.opsForHash().entries(CacheConstants.DEVICE_LASTDATA_CACHE_KEY);
        if (ObjectUtil.isEmpty(hashValues)) {
            log.info("Redis 中无设备数据，任务结束");
            return;
        }
        List<DeviceDataVo> deviceDataList = hashValues.values().stream()
                .map(item -> JSON.parseArray((String) item, DeviceDataVo.class))
                .flatMap(List::stream) // 将多个数组合并为一个流
                .collect(Collectors.toList());

        // 遍历设备数据，逐行校验
        for (DeviceDataVo deviceData : deviceDataList) {
            // 上报时间是否 > 1 分钟
            LocalDateTime reportTime = deviceData.getAlarmTime();
            LocalDateTime now = LocalDateTime.now();
            Duration duration = Duration.between(reportTime, now);
            if (duration.toMinutes() > 1) {
                continue;
            }

            // 获取当前设备的 iot_id
            String deviceIotId = deviceData.getIotId();

            // 本设备合并全部设备规则
            // 筛选"本设备的专属规则" + "通用规则"（未绑定 iot_id 的规则）
            List<AlertRuleVo> deviceRules = alertRuleList.stream()
                    .filter(rule -> deviceIotId.equals(rule.getIotId())
                            || rule.getIotId() == null || rule.getIotId().isEmpty())
                    .collect(Collectors.toList());

            if (ObjectUtil.isEmpty(deviceRules)) {
                continue;
            }
            processAlert(deviceData, deviceRules);
        }
    }

    /**
     * 处理报警规则
     */
    private void processAlert(DeviceDataVo deviceData, List<AlertRuleVo> deviceRules) {
        for (AlertRuleVo rule : deviceRules) {
            // 第一层校验：判断生效时间
            if (!isInEffectiveTime(rule.getAlertEffectivePeriod())) {
                continue;
            }

            // 第二层校验：判断数据阈值
            if (!isReachThreshold(deviceData.getDataValue(), rule.getOperator(), rule.getValue())) {
                // 未达到阈值，删除redis报警数
                String alertCountKey = CacheConstants.ALERT_COUNT_KEY + rule.getId() + ":" + deviceData.getIotId();
                redisTemplate.delete(alertCountKey);
                continue;
            }

            // 第三层校验：判断沉默周期
            String silentKey = CacheConstants.ALERT_SILENT_KEY + rule.getId() + ":" + deviceData.getIotId();
            String silentTime = redisTemplate.opsForValue().get(silentKey);
            if (ObjectUtil.isNotEmpty(silentTime)) {
                // 沉默周期内，不处理报警
                continue;
            }

            // 第四层校验：判断持续周期
            String alertCountKey = CacheConstants.ALERT_COUNT_KEY + rule.getId() + ":" + deviceData.getIotId();
            String alertCountStr = redisTemplate.opsForValue().get(alertCountKey);
            int alertCount = ObjectUtil.isEmpty(alertCountStr) ? 0 : Integer.parseInt(alertCountStr);

            // 当前报警次数 = 已报警次数 + 1
            int currentAlertCount = alertCount + 1;

            if (currentAlertCount >= rule.getDuration()) {
                // 达到持续周期，触发报警
                handleAlertTrigger(deviceData, rule);

                // 重置报警计数
                redisTemplate.delete(alertCountKey);

                // 设置沉默周期
                redisTemplate.opsForValue().set(silentKey, "5", Duration.ofMinutes(rule.getAlertSilentPeriod()));
            } else {
                // 未达到持续周期，更新报警计数
                redisTemplate.opsForValue().set(alertCountKey, String.valueOf(currentAlertCount));
            }
        }
    }

    /**
     * 判断是否在生效时间内
     */
    private boolean isInEffectiveTime(String effectivePeriod) {
        if (ObjectUtil.isEmpty(effectivePeriod)) {
            return true;
        }

        try {
            String[] times = effectivePeriod.split("~");
            LocalTime startTime = LocalTime.parse(times[0]);
            LocalTime endTime = LocalTime.parse(times[1]);
            LocalTime currentTime = LocalTime.now();

            return !currentTime.isBefore(startTime) && !currentTime.isAfter(endTime);
        } catch (Exception e) {
            log.error("解析生效时间失败: {}", effectivePeriod, e);
            return false;
        }
    }

    /**
     * 判断是否达到阈值
     */
    private boolean isReachThreshold(String dataValue, String operator, Float threshold) {
        try {
            double value = Double.parseDouble(dataValue);

            switch (operator) {
                case "<":
                    return value < threshold;
                case "<=":
                    return value <= threshold;
                case ">":
                    return value > threshold;
                case ">=":
                    return value >= threshold;
                case "=":
                    return Math.abs(value - threshold) < 0.001; // 考虑浮点数精度问题
                default:
                    log.warn("未知的操作符: {}", operator);
                    return false;
            }
        } catch (NumberFormatException e) {
            log.error("数据值转换失败: {}", dataValue, e);
            return false;
        }
    }

    /**
     * 处理报警触发
     */
    private void handleAlertTrigger(DeviceDataVo deviceData, AlertRuleVo rule) {
        // 这里实现报警触发后的处理逻辑
        log.info("报警触发: 设备={}, 规则={}", deviceData.getDeviceName(), rule.getAlertRuleName());

    }
}